定义QueryResult

//
// Created by modao on 2021-01-6//

#ifndef TEXT_QUERY_QUERYRESULT_H
#define TEXT_QUERY_QUERYRESULT_H

std::string make_plural(size_t ctr, const std::string &word, const std::string ending)
{
    return (ctr == 1)? word: word + ending;
}
class QueryResult {
friend std::ostream &print(std::ostream&, const QueryResult&);
public:
    using line_no = std::vector<std::string>::size_type;
    QueryResult(std::string s,
                std::shared_ptr<std::set<line_no>> p,
                std::shared_ptr<std::vector<std::string>> f):
                sought(s), lines(p), file(f) { }
    std::shared_ptr<std::vector<std::string>> get_file(){
        return file;
    }

    std::set<line_no>::iterator begin(){
        return lines->begin();
    }

    std::set<line_no>::iterator end(){
        return lines->end();
    }
private:
    std::string sought;
    std::shared_ptr<std::set<line_no>> lines;
    std::shared_ptr<std::vector<std::string>> file;
};

std::ostream &print(std::ostream &os, const QueryResult &qr){
    os << qr.sought << " occurs " << qr.lines->size() << ' '
       << make_plural(qr.lines->size(), "time", "s") << std::endl;
    for(auto num : *qr.lines)
        os << "\t(line " << num + 1 << ") "
           << *(qr.file->begin() + num) << std::endl;
    return os;
}
#endif //TEXT_QUERY_QUERYRESULT_H

定义TextQuery

//
// Created by modao on 2021-01-6//

#ifndef TEXT_QUERY_TEXTQUERY_H
#define TEXT_QUERY_TEXTQUERY_H
#include "QueryResult.h"

class TextQuery {
public:
    using line_no = std::vector<std::string>::size_type;
    TextQuery(std::ifstream&);
    QueryResult query(const std::string&) const;
private:
    std::shared_ptr<std::vector<std::string>> file;
    std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
};
TextQuery::TextQuery(std::ifstream &is): file(new std::vector<std::string>) {
    std::string text;
    while(getline(is, text)){
        file->push_back(text);
        int n = file->size() - 1;
        std::istringstream line(text);
        std::string word;
        while(line >> word){
            auto &lines = wm[word];
            if(!lines)
                lines.reset(new std::set<line_no>);
            lines->insert(n);
        }
    }
}
QueryResult TextQuery::query(const std::string &sought) const {
    static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);

    auto loc = wm.find(sought);
    if(loc == wm.end())
        return QueryResult(sought, nodata, file);
    else
        return QueryResult(sought, loc->second, file);
}
#endif //TEXT_QUERY_TEXTQUERY_H

定义Query接口

//
// Created by modao on 2021-01-7//

#ifndef TEXT_QUERY_QUERY_H
#define TEXT_QUERY_QUERY_H
#include "TextQuery.h"
class Query_base {
    friend class Query;
protected:
    using line_no = TextQuery::line_no;
    virtual ~Query_base() = default;

private:
    virtual QueryResult eval(const TextQuery&) const = 0;
    virtual std::string rep() const = 0;
};

class Query {
private:
    friend Query operator~(const Query &);
    friend Query operator|(const Query&, const Query&);
    friend Query operator&(const Query&, const Query&);
public:
    Query(const std::string&);
    QueryResult eval(const TextQuery &t) const{
        return q->eval(t);
    }
    std::string rep() const {
        return q->rep();
    }
    friend std::ostream &
    operator<<(std::ostream &os, const Query &query){
        return os << query.rep();
    }
private:
    Query(std::shared_ptr<Query_base> query) : q(query){ }
    std::shared_ptr<Query_base> q;
};

class WordQuery: public Query_base {
    friend class Query;
    WordQuery(const std::string &s) : query_word(s){}
    QueryResult eval(const TextQuery &t) const{
        return t.query(query_word);
    }
    std::string rep() const{
        return query_word;
    }
    std::string query_word;
};
inline Query::Query(const std::string &s):q(new WordQuery(s)) {}

class NotQuery: public Query_base{
    friend Query operator~(const Query &);
    NotQuery(const Query &q):query(q){}
    std::string rep() const {
        return "~(" + query.rep() + ")";
    }
    QueryResult eval(const TextQuery &) const;
    Query query;
};
inline Query operator~(const Query &operand){
    return std::shared_ptr<Query_base>(new NotQuery(operand));
}
QueryResult
NotQuery::eval(const TextQuery &text) const {
    auto result = query.eval(text);
    auto ret_lines = std::make_shared<std::set<line_no>>();
    auto beg = result.begin(), end = result.end();
    auto sz = result.get_file()->size();
    for(size_t n = 0; n != sz; ++n){
        if(beg == end || *beg != n)
            ret_lines->insert(n);
        else if(beg != end)
            ++beg;
    }
    return QueryResult(rep(), ret_lines, result.get_file());
}

class BinaryQuery: public Query_base {
protected:
    BinaryQuery(const Query &l, const Query &r, std::string s):
        lhs(l), rhs(r), opSym(s){}
    std::string rep() const {
        return "(" + lhs.rep() + " "
                    +opSym + " "
                    +rhs.rep() + ")";
    }
    Query lhs, rhs;
    std::string opSym;
};

class AndQuery: public BinaryQuery{
    friend Query operator&(const Query&, const Query&);
    AndQuery(const Query &left, const Query &right):
        BinaryQuery(left, right, "&"){}
    QueryResult eval(const TextQuery&) const;
};
inline Query operator&(const Query &lhs, const Query &rhs){
    return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
QueryResult
AndQuery::eval(const TextQuery &text) const {
    auto left = lhs.eval(text), right = rhs.eval(text);
    auto ret_lines = std::make_shared<std::set<line_no>>();
    std::set_intersection(left.begin(), left.end(),
                    right.begin(), right.end(),
                    inserter(*ret_lines, ret_lines->begin()));
    return QueryResult(rep(), ret_lines, left.get_file());
}

class OrQuery: public BinaryQuery{
    friend Query operator|(const Query&, const Query&);
    OrQuery(const Query &left, const Query &right):
        BinaryQuery(left, right, "|"){}
    QueryResult eval(const TextQuery&) const;
};
inline Query operator|(const Query &lhs, const Query &rhs){
    return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
QueryResult
OrQuery::eval(const TextQuery& text) const{
    auto right = rhs.eval(text), left = lhs.eval(text);
    auto ret_lines =
            std::make_shared<std::set<line_no>>(left.begin(), left.end());
    ret_lines->insert(right.begin(), right.end());
    return QueryResult(rep(), ret_lines, left.get_file());
}
#endif //TEXT_QUERY_QUERY_H

编写main函数

#include <fstream>
#include <iostream>
#include <vector>
#include <memory>
#include <map>
#include <set>
#include <string>
#include <algorithm>
#include <sstream>

#include "Query.h"

void runQueries(std::ifstream &infile){
    TextQuery tq(infile);
    while(true){
        std::cout << "enter word to look for"<< std::endl;
        std::string s1,s2,s3;
        std::cin >> s1 >> s2 >> s3;

        Query q0(s1);
        Query q1=~Query(s1);
        Query q2=Query(s1)|Query(s2);
        Query q3=Query(s1)&Query(s2);

        print(std::cout, q0.eval(tq)) << std::endl;
        print(std::cout, q1.eval(tq)) << std::endl;
        print(std::cout, q2.eval(tq)) << std::endl;
        print(std::cout, q3.eval(tq)) << std::endl;
    }
}
int main() {
    //必须使用绝对路径
    std::ifstream file("E:\\clion_workspace\\Text_query\\file.txt");
    runQueries(file);
    return 0;
}

cmake文件

cmake_minimum_required(VERSION 3.12)
project(Text_query)

set(CMAKE_CXX_STANDARD 20)

add_executable(Text_query main.cpp TextQuery.h QueryResult.h Query.h)

file.txt文件

Alice Emma has long flowing red hair.
Her Daddy says when the wind blows
through her hair, it looks almost alive,
like a fiery bird in flight.
A beautiful fiery bird, he tells her,
magical but untamed.
“Daddy, shush, there is no such thing,”
she tells him, at the same time wanting
him to tell her more.
Shyly, she asks, “I mean, Daddy, is there?”